//
//  BIPNode.m
//  RoutingEvaluator
//
//  Created by Christopher Kemsley on 4/15/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#import "BIPNode.h"
#import "BIPLink.h"
using namespace Sim ;



@implementation BIPNode {
	NSMutableArray*		links ;
}
@dynamic links , minimumPowerIncrement , activeLinks , inactiveLinks , inactiveLinksToInactiveNodes ;



- (id)	initWithNodeInfo:(Sim::NodeInfo*)info allLinks:(NSSet*)allOCLinkInfos {
	if ( (self = [super initWithNodeInfo:info]) )
		{
		NSPredicate * p = [NSPredicate predicateWithFormat:@"(endpoints CONTAINS %@)",self] ;
		NSSet * results = [allOCLinkInfos filteredSetUsingPredicate:p] ;
		
		NSSortDescriptor * d = [NSSortDescriptor sortDescriptorWithKey:@"cost" ascending:YES] ;
		id ds = [NSArray arrayWithObject:d] ;
		NSArray * inactive = [results sortedArrayUsingDescriptors:ds] ;
		
		links		=	[inactive mutableCopy] ;
		}
	return self ;
}




- (void)	activateNextLinks {
	NSArray*	inactiveLinks	=	self.inactiveLinks ;
	
	Float64			cost		=	[ [inactiveLinks objectAtIndex:0] cost ] ;
	
	
	// Find the nodes to activate
	
	__block NSRange	range			=	{ 0 , 1 } ;
	
	[inactiveLinks enumerateObjectsUsingBlock:^(id obj,NSUInteger i,BOOL*s){
		Float64 c = [obj cost] ;
		if ( c > cost )
			{
			*s = YES ;
			}
		else
			{
			range.length = i+1 ;
			}
	}] ;
	
	NSIndexSet * set = [NSIndexSet indexSetWithIndexesInRange:range] ;
	
	
	
	// Activate them
	
	NSArray * transfer = [inactiveLinks objectsAtIndexes:set] ;
	for ( BIPLink * link in transfer )
		{
		link.isActive = YES ;
		}
}


- (NSArray*) links {
	return links ;
}
- (NSArray*) activeLinks {
	static NSPredicate * p = 0 ; if(p==0) p = [NSPredicate predicateWithFormat:@"(isActive == YES)"] ;
	return [links filteredArrayUsingPredicate:p] ;
}
- (NSArray*) inactiveLinks {
	static NSPredicate * p = 0 ; if(p==0) p = [NSPredicate predicateWithFormat:@"(isActive == NO)"] ;
	return [links filteredArrayUsingPredicate:p] ;
}
- (NSArray*)	inactiveLinksToInactiveNodes {
	static NSPredicate * p = 0 ; if(p==0) p = [NSPredicate predicateWithBlock:^BOOL(id l,NSDictionary*b){
		BIPLink * link = l ;
		for ( BIPNode * node in link.endpoints )
			{
			if ( node == self ) continue ;
			if ( node.activeLinks.count == 0 )
				return YES ;
			}
		return NO ;
	}] ;
	return [self.inactiveLinks filteredArrayUsingPredicate:p] ;
}


- (Sim::Float64)	minimumPowerIncrement {
	NSArray*	inactiveLinks	=	self.inactiveLinks ;
	NSArray*	activeLinks		=	self.activeLinks ;
	
	if ( inactiveLinks.count == 0 ) return Sim::kFloat64Max ;
	
	OCLinkInfo	*	strongestLink	=	[activeLinks lastObject] ;
	OCLinkInfo	*	nextLink		=	[inactiveLinks objectAtIndex:0] ;
	
	if ( strongestLink == 0 )
		return nextLink.cost ;
	else
		return nextLink.cost - strongestLink.cost ;
}

- (NSString*)	description {
	NSArray*	inactiveLinks	=	self.inactiveLinks ;
	NSArray*	activeLinks		=	self.activeLinks ;
	Float64		increment		=	self.minimumPowerIncrement ;
	
	if ( increment != kFloat64Max )
		return [ [super description] stringByAppendingFormat:@" { inactiveLinks.count: %u , activeLinks.count: %u , minimumPowerIncrement: %.2lf",(unsigned)inactiveLinks.count,(unsigned)activeLinks.count,increment ] ;
	else
		return [ [super description] stringByAppendingFormat:@" { inactiveLinks.count: %u , activeLinks.count: %u , minimumPowerIncrement: infinity",(unsigned)inactiveLinks.count,(unsigned)activeLinks.count ] ;
}



+ (NSSet*)	setWithNodes:(Sim::NodeInfoSet*)set allLinks:(NSSet*)allOCLinkInfos {
	NSMutableSet * output = [NSMutableSet setWithCapacity:set->nodes().size()] ;
	
	std::vector<NodeInfo*>::const_iterator	here	=	set->nodes().begin() ;
	std::vector<NodeInfo*>::const_iterator	end		=	set->nodes().end() ;
	while ( here < end )
		{
		NodeInfo * info = *(here++) ;
		id node = [ [BIPNode alloc] initWithNodeInfo:info allLinks:allOCLinkInfos ] ;
		[output addObject:node] ;
		}
	
	return output ;
}

@end
